
/**
 * @file supporting_executable.cpp
 */

#include "nosal/exec/execution_client.h"
#include "nosal/log/logging.h"
#include "nosal/log/logger.h"

#include <chrono>
#include <thread>
#include <memory>
#include <csignal>
#include <cstring>
#include <iostream>

namespace
{

/**
 * @brief SigTermHandler SIGTERM handler
 */
void SigTermHandler(int);

/**
 * @brief IsSigTermRaised Getter for a flag "Is SIGTERM rased"
 * @return true if the process got SIG_TERM otherwise false
 */
bool IsSigTermRaised();

}  // namespace

/**
 * @brief main
 *
 * @param argc
 * @param argv
 *
 * @note argv[0] is a path to the executable binary
 * @note argv[1] defines reporting-behavior for a Process:
 *               "reporting" for Reporting Processes
 *               "non-reporting" for Non-Reporting Processes
 * @note argv[2] defines "work time"; possible values:
 *               <empty> - endless work (till SIGTERM is raised)
 *               <number> - work time in milliseconds
 *
 * @return
 */
int main(int argc, char** argv)
{
    std::cerr << std::endl << "Starting process " << argv[0] << std::endl;

    if (argc < 2) {
        std::cerr << "Invalid number of arguments";
        return EXIT_FAILURE;
    }

    constexpr char kReporting[] = "reporting";
    constexpr char kNonReporting[] = "non-reporting";

    bool isNonReporting;
    if (std::strcmp(kNonReporting, argv[1]) == 0) {
        isNonReporting = true;
    } else if (std::strcmp(kReporting, argv[1]) == 0) {
        isNonReporting = false;
    } else {
        std::cerr << "Invalid value of reporting-behavior argument";
        return EXIT_FAILURE;
    }

    const bool isSelfTerminating = (argc > 2);
    const std::chrono::milliseconds workTime(isSelfTerminating ? std::stoul(argv[2]) : 0U);

    std::signal(SIGTERM, SigTermHandler);

    netaos::nosal::log::InitLogging("DEMO", argv[0], netaos::nosal::log::LogLevel::kInfo, netaos::nosal::log::LogMode::kConsole);

    std::unique_ptr<::netaos::nosal::exec::ExecutionClient> executionClient;
    if (!isNonReporting) {
        executionClient = std::make_unique<::netaos::nosal::exec::ExecutionClient>();
        executionClient->ReportExecutionState(netaos::nosal::exec::ExecutionState::kRunning);
    }

    typedef std::conditional<std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock>::type clock;

    const auto startTime = clock::now();
    while ((!isSelfTerminating || (clock::now() - startTime) < workTime) && !IsSigTermRaised()) {

        // Using sleep step means that the process exit timeout should be bigger than sleep step
        static const std::chrono::milliseconds kSleepStep(5U);

        std::this_thread::sleep_for(kSleepStep);
    }

    return EXIT_SUCCESS;
}

namespace
{

volatile std::sig_atomic_t gIsSigTermRaised = 0;

void SigTermHandler(int)
{
    gIsSigTermRaised = 1;
}

bool IsSigTermRaised()
{
    return gIsSigTermRaised;
}

}  // namespace
